﻿namespace Rosieks.Web.Flow.Fluent
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Rosieks.Web.Flow.Metadata;

    public class FluentStateRegister<TWebflowModel>
    {
        protected WebflowModel Model { get; private set; }
        protected IList<FluentTransitionRegister<TWebflowModel>> Transitions { get; set; }
        protected string DefaultViewPath { get; set; }

        public FluentStateRegister(WebflowModel model)
        {
            this.Model = model;
            this.Transitions = new List<FluentTransitionRegister<TWebflowModel>>();
            this.DefaultViewPath = "~/Views/{0}/{1}.cshtml";
        }

        public FluentStateRegister<TState, TWebflowModel> State<TState>(string name) where TState : State
        {
            TState state = Activator.CreateInstance<TState>();
            state.Name = name;

            this.Model.States.Add(state);

            return new FluentStateRegister<TState, TWebflowModel>(this.Model, state, this.Transitions);
        }

        public FluentStateRegister<TWebflowModel> WithDefaultViewPath(string viewPath)
        {
            this.DefaultViewPath = viewPath;

            return this;
        }

        public void Execute()
        {
            foreach (var viewState in this.Model.States.OfType<ViewState>().Where(s => s.ViewPath == null))
            {
                viewState.ViewPath = string.Format(this.DefaultViewPath, this.Model.Name, viewState.Name);
            }

            foreach (var item in this.Transitions)
            {
                item.Execute();
            }
        }
    }

    public class FluentStateRegister<TState, TWebflowModel> : FluentStateRegister<TWebflowModel> where TState : State
    {
        public TState State { get; private set; }
        public string ControllerName { get; set; }

        public FluentStateRegister(WebflowModel model, TState state, IList<FluentTransitionRegister<TWebflowModel>> transitions)
            : base(model)
        {
            this.State = state;
            this.Transitions = transitions;
            string controllerName = this.Model.Name + "Controller";
            if (this.Model.Model.Assembly.GetTypes().Any(t => t.Name == controllerName && typeof(FlowController).IsAssignableFrom(t)))
            {
                this.ControllerName = this.Model.Name;
            }
        }

        public FluentStateRegister<TState, TWebflowModel> WithTransisions(Action<FluentTransitionRegister<TWebflowModel>> transisions)
        {
            var register = new FluentTransitionRegister<TWebflowModel>(this.Model, this.State);
            transisions(register);
            this.Transitions.Add(register);

            return this;
        }

        public FluentStateRegister<TState, TWebflowModel> IsFirstStep()
        {
            this.Model.FirstState = this.State;

            return this;
        }

        public FluentStateRegister<TState, TWebflowModel> IsEndStep()
        {
            this.State.IsEndState = true;

            return this;
        }

        public FluentStateRegister<TState, TWebflowModel> WithRoutes(RouteData route)
        {
            this.State.RouteData = route;

            if (!this.State.RouteData.Values.ContainsKey("controller") && this.ControllerName != null)
            {
                this.State.RouteData.Values["controller"] = this.ControllerName;
            }

            if (!this.State.RouteData.Values.ContainsKey("action"))
            {
                this.State.RouteData.Values["action"] = this.State.Name;
            }

            return this;
        }

        public FluentStateRegister<TState, TWebflowModel> WithRoutes(string routeName, object routeValues, string url = null)
        {
            return this.WithRoutes(new RouteData
            {
                Url = url,
                RouteName = routeName,
                Values = new System.Web.Routing.RouteValueDictionary(routeValues),
            });
        }
    }
}
